@page "/"

@using Orleankka
@using Orleankka.Client
@using ProcessManager

@inject IClientActorSystem ActorSystem

<p>
    <input placeholder="job #id" @bind="jobId"/>
    <button class="btn btn-primary" @onclick="StartJob">Start</button>
    <button class="btn btn-warning" @onclick="RestartJob">Restart</button>
    <button class="btn btn-secondary" @onclick="SuspendJob">Suspend</button>
    <button class="btn btn-success" @onclick="ContinueJob">Continue</button>
    <button class="btn btn-danger" @onclick="CancelJob">Cancel</button>
</p>

<p>
    <span><b>Last Action:</b></span>
    <span><em>@lastCommandResult</em></span>
</p>

@if (jobs == null)
{
<p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Id</th>
                <th>Active</th>
                <th>Status</th>
                <th>Previous</th>
                <th>Progress</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var each in jobs)
            {
                <tr>
                    <td>@each.Id</td>
                    <td>@(each.Active ? "Active" : "-")</td>
                    <td>@each.Status</td>
                    <td>@each.Previous</td>
                    <td>@each.Progress</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    List<JobItem> jobs;
    StreamRef<JobEvent> notifications;
    string jobId = null;
    string lastCommandResult;

    protected override async Task OnInitializedAsync()
    {
        jobs = new List<JobItem>();

        notifications = ActorSystem.StreamOf<JobEvent>("notifications", "copier");
        await notifications.Subscribe(async (e, _) =>
        {
            var job = jobs.SingleOrDefault(x => x.Id == e.Id);

            if (job == null)
            {
                job = new JobItem { Id = e.Id};
                jobs.Add(job);
            }

            if (e is StateChanged s)
            {
                job.Status = s.Current;
                job.Previous = s.Previous;
                job.Active = s.Active;
            }
            if (e is ProgressChanged p)
                job.Progress = (int)(p.Progress * 100);

            await InvokeAsync(StateHasChanged);
        });
    }

    Task StartJob()    => Send(new Start());
    Task RestartJob()  => Send(new Restart());
    Task SuspendJob()  => Send(new Suspend());
    Task ContinueJob() => Send(new Continue());
    Task CancelJob()   => Send(new Cancel());

    async Task Send(ActorMessage<ICopier> cmd)
    {
        lastCommandResult = "";
        
        var job = ActorSystem.TypedActorOf<ICopier>(jobId);
        var result = await job.Ask<object>(cmd);
        
        lastCommandResult = result.GetType().Name;
        StateHasChanged();
    }

    class JobItem
    {
        public string Id { get; set; }
        public bool Active { get; set; }
        public string Status { get; set; }
        public string Previous { get; set; }
        public int Progress { get; set; }
    }
}
